<!DOCTYPE html>
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
  <meta name="description" content="tong.li&#39;s blog">
  <meta name="keyword" content="彤哥哥博客，95后技术爱好者,现就职于同程旅行/同程艺龙上海分公司，专注于互联网技术分享的平台。">
  
    <link rel="shortcut icon" href="/css/images/icon.png">
  
  <title>
    
      了解常见的Redis集群方式 | 彤哥哥的博客
    
  </title>
  <link href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <link href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" rel="stylesheet">
  <link href="https://cdn.staticfile.org/highlight.js/9.12.0/styles/tomorrow-night.min.css" rel="stylesheet">
  
<link rel="stylesheet" href="/css/style.css">

  
  <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
  <script src="https://cdn.staticfile.org/geopattern/1.2.3/js/geopattern.min.js"></script>
  <script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js"></script>
  
    
<script src="/js/qrious.js"></script>

  
  
  
  
    <!-- MathJax support START -->
    <script type="text/x-mathjax-config">
      MathJax.Hub.Config({
        tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
          processEscapes: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
        }
      });
    </script>

    <script type="text/x-mathjax-config">
      MathJax.Hub.Queue(function() {
        var all = MathJax.Hub.getAllJax(), i;
        for (i=0; i < all.length; i += 1) {
          all[i].SourceElement().parentNode.className += ' has-jax';
        }
      });
    </script>
    <script type="text/javascript" src="https://cdn.staticfile.org/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
    <!-- MathJax support END -->
  


  
  
    
<script src="/js/local-search.js"></script>


<meta name="generator" content="Hexo 5.4.2"></head>
<div class="wechat-share">
  <img src="/css/images/logo.png" />
</div>
  <body>
    <header class="header fixed-header">
  <div class="header-container">
    <a class="home-link" href="/">
      <div class="logo"></div>
      <span>彤哥哥的博客</span>
    </a>
    <ul class="right-list">
      
        <li class="list-item">
          
            <a href="/" class="item-link">主页</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/series/" class="item-link">分类</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/tags/" class="item-link">标签</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/archives/" class="item-link">归档</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/project/" class="item-link">项目</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/about/" class="item-link">关于</a>
          
        </li>
      
      
        <li class="menu-item menu-item-search right-list">
    <a role="button" class="popup-trigger">
        <i class="fa fa-search fa-fw"></i>
    </a>
</li>
      
    </ul>
    <div class="menu">
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
    </div>
    <div class="menu-mask">
      <ul class="menu-list">
        
          <li class="menu-item">
            
              <a href="/" class="menu-link">主页</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/series/" class="menu-link">分类</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/tags/" class="menu-link">标签</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/archives/" class="menu-link">归档</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/project/" class="menu-link">项目</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/about/" class="menu-link">关于</a>
            
          </li>
        
      </ul>
    </div>
    
      <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
            <span class="search-icon">
                <i class="fa fa-search"></i>
            </span>
            <div class="search-input-container">
                <input autocomplete="off" autocapitalize="off"
                    placeholder="Please enter your keyword(s) to search." spellcheck="false"
                    type="search" class="search-input">
            </div>
            <span class="popup-btn-close">
                <i class="fa fa-times-circle"></i>
            </span>
        </div>
        <div id="search-result">
            <div id="no-result">
                <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
            </div>
        </div>
    </div>
</div>
    
  </div>
</header>

    <div id="article-banner">
  <h2>了解常见的Redis集群方式</h2>
  <p class="post-date">2020-04-01</p>
  <div class="arrow-down">
    <a href="javascript:;"></a>
  </div>
</div>
<main class="app-body flex-box">
  <!-- Article START -->
  <article class="post-article">
    <section class="markdown-content"><h1 id="1-Redis单节点模式"><a href="#1-Redis单节点模式" class="headerlink" title="1. Redis单节点模式"></a>1. Redis单节点模式</h1><p>Redis单节点部署架构，即Redis单机版。</p>
<h2 id="1-1-优缺点对比"><a href="#1-1-优缺点对比" class="headerlink" title="1.1 优缺点对比"></a>1.1 优缺点对比</h2><p>优点：</p>
<ul>
<li><p>架构简单，部署与维护方便；</p>
</li>
<li><p>成本低，数据量小的情况下，性价比高</p>
</li>
</ul>
<p>缺点：</p>
<ul>
<li><p>单点故障严重，数据可靠性和服务可用性无法保证;</p>
</li>
<li><p>完全基于内存，强依赖于物理硬件，大数量下，性能会达到瓶颈。</p>
</li>
<li><p>大数据量下，进程重启后，持久化数据恢复慢。</p>
</li>
</ul>
<h2 id="1-2-单节点安装"><a href="#1-2-单节点安装" class="headerlink" title="1.2 单节点安装"></a>1.2 单节点安装</h2><ol>
<li><p>下载Redis安装程序包并解压，我这里选择目前最新的Redis 5.0.8稳定版(Stable)。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">[root@litong bin]<span class="comment"># wget http://download.redis.io/releases/redis-5.0.8.tar.gz</span></span><br><span class="line">[root@litong bin]<span class="comment"># tar -xzvf redis-5.0.8.tar.gz</span></span><br><span class="line">[root@litong bin]<span class="comment"># ll</span></span><br><span class="line">总用量 1944</span><br><span class="line">drwxrwxr-x. 6 root root    4096 3月  12 23:07 redis-5.0.8</span><br><span class="line">-rw-r--r--. 1 root root 1985757 3月  12 23:08 redis-5.0.8.tar.gz</span><br></pre></td></tr></table></figure></li>
<li><p>我们可以查阅解压目录里README.md文件中Building Redis完成构建安装。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[root@litong redis-5.0.8]<span class="comment"># cd redis-5.0.8/  # 先进入到解压目录里</span></span><br><span class="line">[root@litong redis-5.0.8]<span class="comment"># make # 使用make编译安装，如果命令make缺失，请安装gcc后执行make distclean</span></span><br><span class="line">[root@litong src]<span class="comment"># cd src/  # 构建完成后会生成src目录</span></span><br><span class="line">[root@litong src]<span class="comment"># ll | grep redis-server   # redis-server就是我们最终的安装程序</span></span><br><span class="line">-rwxr-xr-x. 1 root root 8125016 4月   9 10:33 redis-server</span><br></pre></td></tr></table></figure></li>
<li><p>复制一个单结点出来</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">[root@litong src]<span class="comment"># make PREFIX=/usr/local/bin/redis install  # 拷贝安装到/usr/local/bin/redis一份实例</span></span><br><span class="line">    CC Makefile.dep</span><br><span class="line"></span><br><span class="line">Hint: It<span class="string">&#x27;s a good idea to run &#x27;</span>make <span class="built_in">test</span><span class="string">&#x27; ;)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    INSTALL install</span></span><br><span class="line"><span class="string">    INSTALL install</span></span><br><span class="line"><span class="string">    INSTALL install</span></span><br><span class="line"><span class="string">    INSTALL install</span></span><br><span class="line"><span class="string">    INSTALL install</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">[root@litong src]# cd /usr/local/bin/redis/bin/  # 进入安装后可执行目录的</span></span><br><span class="line"><span class="string">[root@litong bin]# ll </span></span><br><span class="line"><span class="string">总用量 32772</span></span><br><span class="line"><span class="string">-rwxr-xr-x. 1 root root 4366824 4月   9 10:49 redis-benchmark</span></span><br><span class="line"><span class="string">-rwxr-xr-x. 1 root root 8125016 4月   9 10:49 redis-check-aof</span></span><br><span class="line"><span class="string">-rwxr-xr-x. 1 root root 8125016 4月   9 10:49 redis-check-rdb</span></span><br><span class="line"><span class="string">-rwxr-xr-x. 1 root root 4807800 4月   9 10:49 redis-cli</span></span><br><span class="line"><span class="string">lrwxrwxrwx. 1 root root      12 4月   9 10:49 redis-sentinel -&gt; redis-server</span></span><br><span class="line"><span class="string">-rwxr-xr-x. 1 root root 8125016 4月   9 10:49 redis-server</span></span><br><span class="line"><span class="string"></span></span><br></pre></td></tr></table></figure></li>
<li><p>启动测试</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">[root@litong redis-5.0.8]<span class="comment"># cd /usr/local/bin/redis-5.0.8/utils/  #redis官方工具</span></span><br><span class="line">[root@litong utils]<span class="comment"># ll | grep install_server.sh </span></span><br><span class="line">-rwxrwxr-x. 1 root root 9567 3月  12 23:07 install_server.sh <span class="comment"># 执行完成交互即可安装到系统服务(开启启动、服务启动)</span></span><br><span class="line">[root@litong ~]<span class="comment"># ps -ef | grep redis # 查看Redis进程</span></span><br><span class="line">root      3440 21316  0 10:58 pts/1    00:00:00 /usr/local/bin/redis/bin/redis-server 127.0.0.1:6379</span><br><span class="line">[root@litong bin]<span class="comment"># ./redis-cli </span></span><br><span class="line">127.0.0.1:6379&gt; ping</span><br><span class="line">PONG</span><br><span class="line">127.0.0.1:6379&gt; <span class="built_in">set</span> name litong</span><br><span class="line">OK</span><br></pre></td></tr></table></figure></li>
</ol>
<p>注意事项：</p>
<p>如果出现本地可以连接，远程连接不了，请进行如下检查设置</p>
<ol>
<li>检查能否ping通redis服务的IP，检查网络是否可达；</li>
<li>关闭防火墙，确保redis端口开发；</li>
<li>在redis.conf文件里将bind 127.0.0.1注释掉；</li>
<li>将保护模式protected-mode yes改为protected-mode no(redis3.2版本以后);</li>
<li>加上配置文件后重启<code>bash nohup ./redis-server redis.conf &amp;</code>即可.</li>
</ol>
<h1 id="2-Redis主从复制模式"><a href="#2-Redis主从复制模式" class="headerlink" title="2. Redis主从复制模式"></a>2. Redis主从复制模式</h1><h2 id="2-1-优缺点对比"><a href="#2-1-优缺点对比" class="headerlink" title="2.1 优缺点对比"></a>2.1 优缺点对比</h2><p>优点：</p>
<ul>
<li><p>一定程度上解决了单点故障问题,读性能迅速提升.</p>
</li>
<li><p>全量数据主从复制,主数据库同步到从数据库,可做读写分离,Redis 2.6.x版本开始,从服务器默认状态只运行读操作.</p>
</li>
<li><p>Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间，客户端仍然可以提交查询或修改请求；</p>
</li>
<li><p>Slave Server同样是以非阻塞的方式完成数据同步。在同步期间，如果有客户端提交查询请求，Redis则返回同步之前的数据；</p>
</li>
</ul>
<p>缺点：</p>
<ul>
<li><p>多节点的全量数据副本.</p>
</li>
<li><p>数据强一致性,降低了系统的可用性.</p>
</li>
<li><p>很难支持在线扩容.</p>
</li>
<li><p>不支持自动容错和恢复功能,需要人工干预,费时费力.</p>
</li>
</ul>
<h2 id="2-2-搭建1主3从的主从复制架构"><a href="#2-2-搭建1主3从的主从复制架构" class="headerlink" title="2.2 搭建1主3从的主从复制架构"></a>2.2 搭建1主3从的主从复制架构</h2><ol>
<li><p>启动三个4个redis实例,端口号分别为8001-8004</p>
</li>
<li><p>启动后为从节点设置主节点</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:8001&gt; REPLICAOF 127.0.0.1 8001 <span class="comment"># 方式1:为后三个从节点设置主节点,需要注意的是5.0.x之前的版本SLAVEOF,5.0.x及其之后的版本用REPLICAOF命令</span></span><br><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$./redis-server --port 8001 --replicaof 127.0.0.1 8001 <span class="comment"># 方式2:启动从节点通过启动命令设置主节点</span></span><br></pre></td></tr></table></figure></li>
<li><p>查询节点角色</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:8001&gt; ROLE <span class="comment"># 查询当前节点的角色,2.8.12版本以后可使用,复杂度为O(1)</span></span><br><span class="line">1) <span class="string">&quot;master&quot;</span> <span class="comment"># 这是一个主节点</span></span><br><span class="line">2) (<span class="built_in">integer</span>) 101  <span class="comment"># 复制的偏移量为101</span></span><br><span class="line">3) 1) <span class="string">&quot;127.0.0.1&quot;</span>   <span class="comment"># 第一个从节点的IP地址</span></span><br><span class="line">   2) <span class="string">&quot;8002&quot;</span>   <span class="comment"># 第一个从节点的端口号</span></span><br><span class="line">   3) <span class="string">&quot;101&quot;</span>   <span class="comment"># 复制的偏移量为101</span></span><br><span class="line">4) 1) <span class="string">&quot;127.0.0.1&quot;</span>   <span class="comment"># 第二个从节点的IP地址</span></span><br><span class="line">   2) <span class="string">&quot;8003&quot;</span>   <span class="comment"># 第二个从节点的端口号</span></span><br><span class="line">   3) <span class="string">&quot;101&quot;</span>   <span class="comment"># 复制的偏移量为101</span></span><br><span class="line">5) 1) <span class="string">&quot;127.0.0.1&quot;</span>   <span class="comment"># 第三个从节点的IP地址</span></span><br><span class="line">   2) <span class="string">&quot;8003&quot;</span>   <span class="comment"># 第三个从节点的端口号</span></span><br><span class="line">   3) <span class="string">&quot;101&quot;</span>   <span class="comment"># 复制的偏移量为101</span></span><br><span class="line">127.0.0.1:8002&gt; ROLE <span class="comment"># 查询当前节点的角色</span></span><br><span class="line">1) <span class="string">&quot;slave&quot;</span> <span class="comment"># 这是一个从节点</span></span><br><span class="line">2) <span class="string">&quot;127.0.0.1&quot;</span>  <span class="comment"># 主节点IP</span></span><br><span class="line">3) (<span class="built_in">integer</span>) 8001   <span class="comment"># 主节点的端口号</span></span><br><span class="line">4) <span class="string">&quot;connected&quot;</span> <span class="comment"># 主节点在线,已连接到主节点</span></span><br><span class="line">5) <span class="string">&quot;101&quot;</span>   <span class="comment"># 复制的偏移量为101</span></span><br></pre></td></tr></table></figure></li>
<li><p>测试使用</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:8001&gt; <span class="built_in">set</span> name litong <span class="comment"># 在主服务set name</span></span><br><span class="line">ok</span><br><span class="line">127.0.0.1:8002&gt; get name <span class="comment"># 在从服务get name</span></span><br><span class="line"><span class="string">&quot;litong&quot;</span></span><br><span class="line">127.0.0.1:8003&gt; get name  <span class="comment"># 在从服务get name</span></span><br><span class="line"><span class="string">&quot;litong&quot;</span></span><br></pre></td></tr></table></figure></li>
</ol>
<p>注意:</p>
<ul>
<li><p>在执行了REPLICAOF操作后,主从节点将执行数据同步操作,从服务器的数据将会被清空.注意从数据库历史数据备份.</p>
</li>
<li><p>复杂度：REPLICAOF命令本身的复杂度为O(1)，但它引起的异步复制操作的复杂度为O(N)，其中N为主服务器包含的键值对总数量。REPLICAOF no one命令的复杂度为O(1)。</p>
</li>
<li><p>REPLICAOF no one, 使当前从节点停止复制,数据不会清空</p>
</li>
</ul>
<h2 id="2-3-主从复制同步过程原理"><a href="#2-3-主从复制同步过程原理" class="headerlink" title="2.3 主从复制同步过程原理"></a>2.3 主从复制同步过程原理</h2><h3 id="2-3-1-完整同步"><a href="#2-3-1-完整同步" class="headerlink" title="2.3.1 完整同步"></a>2.3.1 完整同步</h3><p>当一个Redis服务器接收到REPLICAOF命令，开始对另一个服务器进行复制的时候，主从服务器会执行以下操作：</p>
<p>1）主服务器执行BGSAVE命令，生成一个RDB文件，并使用缓冲区存储起在BGSAVE命令之后执行的所有写命令。</p>
<p>2）当RDB文件创建完毕，主服务器会通过套接字将RDB文件传送给从服务器。</p>
<p>3）从服务器在接收完主服务器传送过来的RDB文件之后，就会载入这个RDB文件，从而获得主服务器在执行BGSAVE命令时的所有数据。</p>
<p>4）当从服务器完成RDB文件载入操作，并开始上线接受命令请求时，主服务器就会把之前存储在缓存区中的所有写命令发送给从服务器执行。</p>
<ol start="5">
<li><p>如果主服务接受到从节点复制请求时已经完成一次RDB的创建,并且RDB文件之后没有发生任何改变,那么直接重用这个RDB文件给从服务器同步数据。</p>
</li>
<li><p>如果有多个从服务器请求主服务同步数据,恰好此时,主服务在创建RDB文件,那么这些从服务器的同步请求全部载入队列,等RDB创建完成后,再把它发送给队列中所有的从服务器。</p>
</li>
</ol>
<h3 id="2-3-2-在线更新"><a href="#2-3-2-在线更新" class="headerlink" title="2.3.2 在线更新"></a>2.3.2 在线更新</h3><ol>
<li><p>当主节点有数据写入,从节点还没同步数据的时候,主从数据也不是永久一致的。</p>
</li>
<li><p>每当主服务器执行完一个写命令之后，它就会将相同的写命令或者具有相同效果的写命令发送给从服务器执行。</p>
</li>
<li><p>因为完整同步之后的主从服务器在执行最新出现的写命令之前，两者的数据库是完全相同的，而导致两者数据库出现不一致的正是最新被执行的写命令，因此从服务器只要接收并执行主服务器发来的写命令，就可以让自己的数据库重新与主服务器数据库保持一致。</p>
</li>
<li><p>需要注意的是在线更新是异步更新的,要求强一致性的程序只能从主节点读取数据。比如主节点在执行完写命令后向从节点发送相同的写命令,万一中间主节点出现故障,可能会导致数据不一致的情况。</p>
</li>
</ol>
<h3 id="2-3-3-增量同步"><a href="#2-3-3-增量同步" class="headerlink" title="2.3.3 增量同步"></a>2.3.3 增量同步</h3><p>在Redis2.8.x版本以前,假设出现主从数据不一致的情况,它们必须通过完整复制重新同步数据,这种重新同步方法是非常浪费资源的。</p>
<p>在Redis2.8.x开始支持增量。当一个Redis服务器成为另一个服务器的主服务器时，它会把每个被执行的写命令都记录到一个特定长度的先进先出队列中。</p>
<p>● 当断线的从服务器尝试重新连接主服务器的时候，主服务器将检查从服务器断线期间，被执行的那些写命令是否仍然保存在队列里面。如果是，那么主服务器就会直接把从服务器缺失的那些写命令发送给从服务器执行，从服务器通过执行这些写命令就可以重新与主服务器保持一致，这样就避免了重新进行完整同步的麻烦。</p>
<p>● 如果从服务器缺失的那些写命令已经不存在于队列当中，那么主从服务器将进行一次完整同步。</p>
<p>● Redis为这个队列设置的默认大小为1MB，用户也可以根据自己的需要，通过配置选项repl-backlog-size来修改这个队列的大小。</p>
<h3 id="2-3-4-无磁盘复制"><a href="#2-3-4-无磁盘复制" class="headerlink" title="2.3.4 无磁盘复制"></a>2.3.4 无磁盘复制</h3><p>主从复制过程中需要主节点创建RDB快照文件,当数据量越大的时候,RDB文件占用的磁盘空间越大,磁盘IO和网络IO是制约同步效率的两大因素。</p>
<p>从2.8.18版本开始引入无磁盘复制特性:启用了这个特性的主服务器在接收到REPLICAOF命令时将不会再在本地创建RDB文件，而是会派生出一个子进程，然后由子进程通过套接字直接将RDB文件写入从服务器。这样主服务器就可以在不创建RDB文件的情况下，完成与从服务器的数据同步。</p>
<p>如果我们使用无磁盘复制,我们将repl-diskless-sync改为yes即可。</p>
<p>需要注意的是无磁盘复制只是避免在主节点创建RDB文件,从节点仍然创建RDB文件进行恢复,该功能目前无法完全无磁盘复制.</p>
<h3 id="2-3-5-主从复制设置优化"><a href="#2-3-5-主从复制设置优化" class="headerlink" title="2.3.5 主从复制设置优化"></a>2.3.5 主从复制设置优化</h3><p>假设我们想要让主服务器只在拥有至少3个从服务器，并且这些从服务器与主服务器最后一次成功通信的间隔不超过10s的情况下才执行写命令，那么可以使用配置选项：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">min-replicas-max-lag 10</span><br><span class="line">min-replicas-to-write 3</span><br></pre></td></tr></table></figure>

<h2 id="2-4-主从复制故障问题"><a href="#2-4-主从复制故障问题" class="headerlink" title="2.4 主从复制故障问题"></a>2.4 主从复制故障问题</h2><p>如果在主从复制架构中出现宕机的情况，需要分情况看：</p>
<h3 id="2-4-1-从Redis宕机"><a href="#2-4-1-从Redis宕机" class="headerlink" title="2.4.1 从Redis宕机"></a>2.4.1 从Redis宕机</h3><ol>
<li><p>这个相对而言比较简单，在Redis中从库重新启动后会自动加入到主从架构中，自动完成同步数据；</p>
</li>
<li><p>问题？ 如果从库在断开期间，主库的变化不大，从库再次启动后，主库依然会将所有的数据做RDB操作吗？还是增量更新？（从库有做持久化的前提下）</p>
<p> i.不会的，因为在Redis2.8版本后就实现了，主从断线后恢复的情况下实现增量复制。</p>
</li>
</ol>
<h3 id="2-4-2-主Redis宕机"><a href="#2-4-2-主Redis宕机" class="headerlink" title="2.4.2 主Redis宕机"></a>2.4.2 主Redis宕机</h3><ol>
<li><p>这个相对而言就会复杂一些，需要以下2步才能完成</p>
<p> i.第一步，在从数据库中执行SLAVEOF NO ONE命令，断开主从关系并且提升为主库继续服务；</p>
<p> ii.第二步，将主库重新启动后，执行SLAVEOF命令，将其设置为其他库的从库，这时数据就能更新回来；</p>
</li>
<li><p>这个手动完成恢复的过程其实是比较麻烦的并且容易出错，有没有好办法解决呢？当前有的，Redis提供的哨兵（sentinel）的功能。</p>
</li>
</ol>
<h1 id="3-Redis哨兵模式"><a href="#3-Redis哨兵模式" class="headerlink" title="3. Redis哨兵模式"></a>3. Redis哨兵模式</h1><h2 id="3-1-优缺点对比"><a href="#3-1-优缺点对比" class="headerlink" title="3.1 优缺点对比"></a>3.1 优缺点对比</h2><p>优点:</p>
<ul>
<li> Sentinel可以监视Redis主服务器,一旦master服务器正常或因故下线,从服务器可以自动升级为主服务器</li>
<li>部署稍简单,故障自动转移,无需人工干预.</li>
</ul>
<p>缺点:</p>
<ul>
<li>资源浪费，Redis 数据节点中 slave 节点作为备份节点不提供服务;</li>
<li>不能解决读写分离问题，实现起来相对复杂。</li>
<li>要想完全实现Redis的高可用,Sentinel必须也是高可用,即2n+1多个节点(Sentinel网格).</li>
</ul>
<h2 id="3-2-Sentinel搭建使用"><a href="#3-2-Sentinel搭建使用" class="headerlink" title="3.2 Sentinel搭建使用"></a>3.2 Sentinel搭建使用</h2><ol>
<li><p>创建sentinel.conf配置文件</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sentinel monitor master_db 127.0.0.1 6379 1 <span class="comment"># 监视127.0.0.1:6379这台名为master_db的master redis ,1表示这个服务器下线所需sentinel的数量</span></span><br></pre></td></tr></table></figure></li>
<li><p>启动sentinel</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./redis-sentinel  ./sentinel.conf <span class="comment"># 启动哨兵,监视主服务器,启动后日志可以看到主从节点信息</span></span><br></pre></td></tr></table></figure></li>
<li><p>下线master,自动切换master,实现故障转移</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">./redis-cli -h 127.0.0.1 -p 6379  <span class="comment"># 进入到主服务器</span></span><br><span class="line">127.0.0.1:8001&gt; shutdown  <span class="comment"># 下线主服务器</span></span><br></pre></td></tr></table></figure></li>
<li><p>稍等一会,查看其他某个从节点的服务器角色自动升级到主服务器</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">./redis-cli -h 127.0.0.1 -p 6379  <span class="comment"># 进入到主服务器</span></span><br><span class="line">127.0.0.1:6377&gt; ROLE <span class="comment"># 查询当前节点的角色,2.8.12版本以后可使用,复杂度为O(1)</span></span><br><span class="line">1) <span class="string">&quot;master&quot;</span> <span class="comment"># 这是一个主节点</span></span><br><span class="line">2) (<span class="built_in">integer</span>) 240  <span class="comment"># 复制的偏移量为101</span></span><br><span class="line">3) 1) <span class="string">&quot;127.0.0.1&quot;</span>   <span class="comment"># 第一个从节点的IP地址</span></span><br><span class="line">   2) <span class="string">&quot;6378&quot;</span>   <span class="comment"># 第一个从节点的端口号</span></span><br><span class="line">   3) <span class="string">&quot;240&quot;</span>   <span class="comment"># 复制的偏移量为101</span></span><br></pre></td></tr></table></figure></li>
</ol>
<h1 id="4-Redis-Cluster模式"><a href="#4-Redis-Cluster模式" class="headerlink" title="4. Redis Cluster模式"></a>4. Redis Cluster模式</h1><p>Redis集群是Redis 3.0版本开始正式引入的功能，它给用户带来了在线扩展Redis系统读写性能的能力，而Redis 5.0更是在集群原有功能的基础上，进一步添加了更多新功能，并且对原有功能做了相当多的优化，使得整个集群系统更简单、易用和高效。</p>
<h2 id="4-1-优缺点对比"><a href="#4-1-优缺点对比" class="headerlink" title="4.1 优缺点对比"></a>4.1 优缺点对比</h2><p>优点：</p>
<ul>
<li><p>无中心架构；</p>
</li>
<li><p>数据按slot插槽动态分散存储，解决主从模式全量数据复制的问题，可扩展性强；</p>
</li>
<li><p>可以做到不停服，可动态添加或删除节点；</p>
</li>
<li><p>部分节点不可用时，集群仍可用，高可用性大大提高；</p>
</li>
<li><p>集群本身丰富的工具和命令，运维成本低。</p>
</li>
</ul>
<p>缺点：</p>
<ul>
<li><p>主节点与从节点的数据通过异步复制，不保证数据强一致性，在极端情况(主节点长时间挂、网络分区)下，很有可能丢失正在写入数据。</p>
</li>
<li><p>没有大量的生产实践，出了问题无法从根本入手。</p>
</li>
</ul>
<h2 id="4-2-基本特性"><a href="#4-2-基本特性" class="headerlink" title="4.2 基本特性"></a>4.2 基本特性</h2><h3 id="4-2-1-复制与高可用"><a href="#4-2-1-复制与高可用" class="headerlink" title="4.2.1 复制与高可用"></a>4.2.1 复制与高可用</h3><p>Redis Cluster与单机版Redis服务器一样，也提供了主从复制功能。</p>
<p>在Redis Cluster中，其中主节点（master node）负责处理客户端发送的读写命令请求，而从节点（replica/slave node）</p>
<p>则负责对主节点进行复制。</p>
<p>除了复制功能之外，Redis Cluster还提供了类似于单机版Redis Sentinel的功能，以此来为集群提供高可用特性。简单来说，集群中的各个节点将互相监视各自的运行状况，并在某个主节点下线时，通过提升该节点的从节点为新主节点来继续提供服务。</p>
<h3 id="4-2-2-分片与重分片"><a href="#4-2-2-分片与重分片" class="headerlink" title="4.2.2 分片与重分片"></a>4.2.2 分片与重分片</h3><p>Redis Cluster通过将数据库分散存储到多个节点上来平衡各个节点的负载压力。</p>
<p>Redis Cluster会将整个数据库空间划分为16384个槽(slot)来实现数据分片,而集群中的各个主节点则会分别负责处理其中的一部分槽。</p>
<p>当用户尝试将一个键存储到集群中时，客户端会先计算出键所属的槽，接着在记录集群节点槽分布的映射表中找出处理该槽的节点，最后再将键存储到相应的节点中</p>
<p>当用户想要向集群添加新节点时，只需要向Redis Cluster发送几条简单的命令，集群就会将相应的槽以及槽中存储的数据迁移至新节点。</p>
<p>与此类似，当用户想要从集群中移除已存在的节点时，被移除的节点也会将自己负责处理的槽以及槽中数据转交给集群中的其他节点负责。</p>
<p>最重要的是，无论是向集群添加新节点还是从集群中移除已有节点，整个重分片（reshard）过程都可以在线进行，Redis Cluster无须因此而停机</p>
<h3 id="4-2-3-高性能"><a href="#4-2-3-高性能" class="headerlink" title="4.2.3 高性能"></a>4.2.3 高性能</h3><p>Redis Cluster采用无代理模式，客户端发送的所有命令都会直接交由节点执行。</p>
<p>对于经过优化的集群客户端来说，客户端发送的命令在绝大部分情况下都不需要实施转向，或者仅需要一次转向，因此在Redis Cluster中执行命令的性能(不考虑节点之间互通信息带来的性能损耗之外)与在单机Redis服务器上执行命令的性能非常接近。</p>
<p>从理论上来讲，集群每增加一倍数量的主节点，集群对于命令请求的处理性能就会提高一倍。</p>
<h2 id="4-3-Redis-Cluster架构"><a href="#4-3-Redis-Cluster架构" class="headerlink" title="4.3 Redis Cluster架构"></a>4.3 Redis Cluster架构</h2><ol>
<li>所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.</li>
<li>节点的fail是通过集群中超过半数的节点检测失效时才生效.</li>
<li>客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可</li>
<li>redis-cluster把所有的物理节点映射到[0-16383]slot（插槽）上,cluster 负责维护node&lt;-&gt;slot&lt;-&gt;value</li>
</ol>
<h2 id="4-4-手动搭建Redis-Cluster"><a href="#4-4-手动搭建Redis-Cluster" class="headerlink" title="4.4 手动搭建Redis Cluster"></a>4.4 手动搭建Redis Cluster</h2><ol>
<li><p>创建集群目录和节点目录</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ <span class="built_in">mkdir</span> redis-cluster <span class="comment">#  创建集群根目录</span></span><br><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ <span class="built_in">cd</span> redis-cluster/ <span class="comment"># </span></span><br><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ <span class="built_in">mkdir</span> node1 node2 node3 node4 node5 node6 <span class="comment"># 创建6个(3主3从)节点目录</span></span><br></pre></td></tr></table></figure></li>
<li><p>为每个节点创建redis.conf配置文件,并为每个节点设置配置,端口设置为7001-7006</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 节点端口号</span></span><br><span class="line">port 7001</span><br><span class="line"><span class="comment"># 是否启用集群</span></span><br><span class="line">cluster-enabled <span class="built_in">yes</span></span><br><span class="line"><span class="comment"># 集群节点的超时时间</span></span><br><span class="line">cluster-node-timeout 5000</span><br><span class="line"><span class="comment"># 开启AOF持久化</span></span><br><span class="line">appendonly <span class="built_in">yes</span></span><br><span class="line"><span class="comment"># 保存数据的AOF文件名称</span></span><br><span class="line">appendfilename <span class="string">&quot;appendonly.aof&quot;</span></span><br><span class="line"><span class="comment"># Redis后台运行</span></span><br><span class="line">daemonize <span class="built_in">yes</span></span><br><span class="line"><span class="comment"># 日志存放路径</span></span><br><span class="line">logfile <span class="string">&quot;./node1.log&quot;</span></span><br></pre></td></tr></table></figure></li>
<li><p>复制redis-server和redis-cli可执行文件到redis-cluster目录</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ <span class="built_in">cp</span> /media/litong/软件/programs/tools/redis/redis-5.0.8/src/redis-server ./</span><br><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ <span class="built_in">cp</span> /media/litong/软件/programs/tools/redis/redis-5.0.8/src/redis-cli ./</span><br><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ <span class="built_in">ls</span></span><br><span class="line">node1  node2  node3  node4  node5  node6  redis-server  redis-cli</span><br></pre></td></tr></table></figure></li>
<li><p>启动6个redis实例,这里以第一个节点启动,其他节点类似启动</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ cd node1</span><br><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ ../redis-server ./redis.conf</span><br><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster/node6$ ps -ef | grep redis</span><br><span class="line">litong    4748     1  0 19:36 ?        00:00:00 ../redis-server *:7001 [cluster]</span><br><span class="line">litong    8987     1  0 19:37 ?        00:00:00 ../redis-server *:7002 [cluster]</span><br><span class="line">litong   10563     1  0 19:38 ?        00:00:00 ../redis-server *:7003 [cluster]</span><br><span class="line">litong   11696     1  0 19:38 ?        00:00:00 ../redis-server *:7004 [cluster]</span><br><span class="line">litong   15806     1  0 19:39 ?        00:00:00 ../redis-server *:7005 [cluster]</span><br><span class="line">litong   16959     1  0 19:39 ?        00:00:00 ../redis-server *:7006 [cluster]</span><br></pre></td></tr></table></figure></li>
<li><p>为当前6个实例创建集群,并分配槽</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ ./redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 --cluster-replicas 1</span><br><span class="line">&gt;&gt;&gt; Performing hash slots allocation on 6 nodes...</span><br><span class="line">Master[0] -&gt; Slots 0 - 5460</span><br><span class="line">Master[1] -&gt; Slots 5461 - 10922</span><br><span class="line">Master[2] -&gt; Slots 10923 - 16383</span><br><span class="line">Adding replica 127.0.0.1:7005 to 127.0.0.1:7001</span><br><span class="line">Adding replica 127.0.0.1:7006 to 127.0.0.1:7002</span><br><span class="line">Adding replica 127.0.0.1:7004 to 127.0.0.1:7003</span><br><span class="line">&gt;&gt;&gt; Trying to optimize slaves allocation for anti-affinity</span><br><span class="line">[WARNING] Some slaves are in the same host as their master</span><br><span class="line">M: dd6a5286d3f8a739c486b6c4f6adc42ac59564c1 127.0.0.1:7001</span><br><span class="line">   slots:[0-5460] (5461 slots) master</span><br><span class="line">M: dc915340a56265b785a0aa60b1d4a8def8bdf294 127.0.0.1:7002</span><br><span class="line">   slots:[5461-10922] (5462 slots) master</span><br><span class="line">M: 2cb729c0b5401be36c370d7d62de8fa2db1a3638 127.0.0.1:7003</span><br><span class="line">   slots:[10923-16383] (5461 slots) master</span><br><span class="line">S: 17379fe77de821b38e3ba18ce6c86d81e60dda7f 127.0.0.1:7004</span><br><span class="line">   replicates dc915340a56265b785a0aa60b1d4a8def8bdf294</span><br><span class="line">S: 18b35efcfc2741a8c6fa120464b19f5e78cbaf74 127.0.0.1:7005</span><br><span class="line">   replicates 2cb729c0b5401be36c370d7d62de8fa2db1a3638</span><br><span class="line">S: 04cfbd2b01cd304281b1ef2d120b112b55b67d51 127.0.0.1:7006</span><br><span class="line">   replicates dd6a5286d3f8a739c486b6c4f6adc42ac59564c1</span><br></pre></td></tr></table></figure>

<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">Can I set the above configuration? (type &#x27;yes&#x27; to accept): yes</span><br><span class="line">&gt;&gt;&gt; Nodes configuration updated</span><br><span class="line">&gt;&gt;&gt; Assign a different config epoch to each node</span><br><span class="line">&gt;&gt;&gt; Sending CLUSTER MEET messages to join the cluster</span><br><span class="line">Waiting for the cluster to join</span><br><span class="line">....</span><br><span class="line">&gt;&gt;&gt; Performing Cluster Check (using node 127.0.0.1:7001)</span><br><span class="line">M: dd6a5286d3f8a739c486b6c4f6adc42ac59564c1 127.0.0.1:7001</span><br><span class="line">   slots:[0-5460] (5461 slots) master</span><br><span class="line">   1 additional replica(s)</span><br><span class="line">S: 17379fe77de821b38e3ba18ce6c86d81e60dda7f 127.0.0.1:7004</span><br><span class="line">   slots: (0 slots) slave</span><br><span class="line">   replicates dc915340a56265b785a0aa60b1d4a8def8bdf294</span><br><span class="line">S: 04cfbd2b01cd304281b1ef2d120b112b55b67d51 127.0.0.1:7006</span><br><span class="line">   slots: (0 slots) slave</span><br><span class="line">   replicates dd6a5286d3f8a739c486b6c4f6adc42ac59564c1</span><br><span class="line">M: dc915340a56265b785a0aa60b1d4a8def8bdf294 127.0.0.1:7002</span><br><span class="line">   slots:[5461-10922] (5462 slots) master</span><br><span class="line">   1 additional replica(s)</span><br><span class="line">S: 18b35efcfc2741a8c6fa120464b19f5e78cbaf74 127.0.0.1:7005</span><br><span class="line">   slots: (0 slots) slave</span><br><span class="line">   replicates 2cb729c0b5401be36c370d7d62de8fa2db1a3638</span><br><span class="line">M: 2cb729c0b5401be36c370d7d62de8fa2db1a3638 127.0.0.1:7003</span><br><span class="line">   slots:[10923-16383] (5461 slots) master</span><br><span class="line">   1 additional replica(s)</span><br><span class="line">[OK] All nodes agree about slots configuration.</span><br><span class="line">&gt;&gt;&gt; Check for open slots...</span><br><span class="line">&gt;&gt;&gt; Check slots coverage...</span><br><span class="line">[OK] All 16384 slots covered</span><br></pre></td></tr></table></figure></li>
<li><p>查询集群状态以及集群节点信息</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ ./redis-cli -p 7001</span><br><span class="line">127.0.0.1:7001&gt; info replication</span><br><span class="line"># Replication</span><br><span class="line">role:master</span><br><span class="line">connected_slaves:1</span><br><span class="line">slave0:ip=127.0.0.1,port=7006,state=online,offset=448,lag=0</span><br><span class="line">master_replid:315becdb2f224589cad3ab226c9101f1780ec071</span><br><span class="line">master_replid2:0000000000000000000000000000000000000000</span><br><span class="line">master_repl_offset:448</span><br><span class="line">second_repl_offset:-1</span><br><span class="line">repl_backlog_active:1</span><br><span class="line">repl_backlog_size:1048576</span><br><span class="line">repl_backlog_first_byte_offset:1</span><br><span class="line">repl_backlog_histlen:448</span><br><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ ./redis-cli -h 127.0.0.1 -p 7001 cluster nodes</span><br><span class="line">17379fe77de821b38e3ba18ce6c86d81e60dda7f 127.0.0.1:7004@17004 slave dc915340a56265b785a0aa60b1d4a8def8bdf294 0 1586606499545 4 connected</span><br><span class="line">dd6a5286d3f8a739c486b6c4f6adc42ac59564c1 127.0.0.1:7001@17001 myself,master - 0 1586606499000 1 connected 0-5460</span><br><span class="line">04cfbd2b01cd304281b1ef2d120b112b55b67d51 127.0.0.1:7006@17006 slave dd6a5286d3f8a739c486b6c4f6adc42ac59564c1 0 1586606499645 6 connected</span><br><span class="line">dc915340a56265b785a0aa60b1d4a8def8bdf294 127.0.0.1:7002@17002 master - 0 1586606499545 2 connected 5461-10922</span><br><span class="line">18b35efcfc2741a8c6fa120464b19f5e78cbaf74 127.0.0.1:7005@17005 slave 2cb729c0b5401be36c370d7d62de8fa2db1a3638 0 1586606500647 5 connected</span><br><span class="line">2cb729c0b5401be36c370d7d62de8fa2db1a3638 127.0.0.1:7003@17003 master - 0 1586606499000 3 connected 10923-16383</span><br></pre></td></tr></table></figure></li>
<li><p>关闭集群,可整理为shell脚本</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ ./redis-cli -c -p 7001 shutdown</span><br><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ ./redis-cli -c -p 7002 shutdown</span><br><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ ./redis-cli -c -p 7003 shutdown</span><br><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ ./redis-cli -c -p 7004 shutdown</span><br><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ ./redis-cli -c -p 7005 shutdown</span><br><span class="line">litong@LT:/media/litong/软件/programs/tools/redis/redis-cluster$ ./redis-cli -c -p 7006 shutdown</span><br></pre></td></tr></table></figure></li>
</ol>
<h2 id="4-5-集群故障机制"><a href="#4-5-集群故障机制" class="headerlink" title="4.5 集群故障机制"></a>4.5 集群故障机制</h2><ol>
<li><p>集群中的每个节点都会定期的向其它节点发送PING命令，并且通过有没有收到回复判断目标节点是否下线；</p>
</li>
<li><p>集群中每一秒就会随机选择5个节点，然后选择其中最久没有响应的节点放PING命令；</p>
</li>
<li><p>如果一定时间内目标节点都没有响应，那么该节点就认为目标节点疑似下线；</p>
</li>
<li><p>当集群中的节点超过半数认为该目标节点疑似下线，那么该节点就会被标记为下线；</p>
</li>
<li><p>当集群中的任何一个节点下线，就会导致插槽区有空档，不完整，那么该集群将不可用；</p>
</li>
<li><p>如何解决上述问题？<br>6.1 在Redis集群中可以使用主从模式实现某一个节点的高可用 </p>
<p>6.2 当该节点（master）宕机后，集群会将该节点的从数据库（slave）转变为（master）继续完成集群服务；</p>
</li>
</ol>
<h1 id="5-自研Redis代理中间件"><a href="#5-自研Redis代理中间件" class="headerlink" title="5. 自研Redis代理中间件"></a>5. 自研Redis代理中间件</h1><h2 id="5-1-Codis代理中间件"><a href="#5-1-Codis代理中间件" class="headerlink" title="5.1 Codis代理中间件"></a>5.1 Codis代理中间件</h2><h3 id="5-1-2-Codis简介"><a href="#5-1-2-Codis简介" class="headerlink" title="5.1.2 Codis简介"></a>5.1.2 Codis简介</h3><p>Codis 是一个分布式 <a target="_blank" rel="noopener" href="https://www.oschina.net/p/redis">Redis</a> 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 (不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务.</p>
<p>Codis 由四部分组成:</p>
<ul>
<li>Codis Proxy   (codis-proxy)</li>
<li>Codis Manager (codis-config)</li>
<li>Codis Redis   (codis-server)</li>
<li>ZooKeeper</li>
</ul>
<p>codis-proxy 是客户端连接的 Redis 代理服务, codis-proxy 本身实现了 Redis 协议, 表现得和一个原生的 Redis 没什么区别 (就像 <a target="_blank" rel="noopener" href="http://www.oschina.net/p/twemproxy">Twemproxy</a>), 对于一个业务来说, 可以部署多个 codis-proxy, codis-proxy 本身是无状态的.</p>
<p>codis-config 是 Codis 的管理工具, 支持包括, 添加/删除 Redis 节点, 添加/删除 Proxy 节点, 发起数据迁移等操作. codis-config 本身还自带了一个 http server, 会启动一个 dashboard, 用户可以直接在浏览器上观察 Codis 集群的运行状态.</p>
<p>codis-server 是 Codis 项目维护的一个 Redis 分支, 基于 2.8.13 开发, 加入了 slot 的支持和原子的数据迁移指令. Codis 上层的 codis-proxy 和 codis-config 只能和这个版本的 Redis 交互才能正常运行.</p>
<p>Codis 依赖 ZooKeeper 来存放数据路由表和 codis-proxy 节点的元信息, codis-config 发起的命令都会通过 ZooKeeper 同步到各个存活的 codis-proxy.</p>
<p>Codis 支持按照 Namespace 区分不同的产品, 拥有不同的 product name 的产品, 各项配置都不会冲突.</p>
<p>目前 Codis 已经是稳定阶段，目前<a target="_blank" rel="noopener" href="http://www.wandoujia.com/">豌豆荚</a>已经在使用该系统。</p>
<h3 id="5-1-2-优缺点对比"><a href="#5-1-2-优缺点对比" class="headerlink" title="5.1.2 优缺点对比"></a>5.1.2 优缺点对比</h3><p>优点:</p>
<ul>
<li>自动平衡</li>
<li>使用非常简单</li>
<li>图形化的面板和管理工具</li>
<li>支持绝大多数 Redis 命令，完全兼容 <a target="_blank" rel="noopener" href="http://www.oschina.net/p/twemproxy">twemproxy</a></li>
<li>支持 Redis 原生客户端</li>
<li>安全而且透明的数据移植，可根据需要轻松添加和删除节点</li>
<li>提供命令行接口</li>
<li>RESTful APIs</li>
</ul>
<p>缺点:</p>
<ul>
<li>增加一层代理,网络开销大</li>
<li>瓶颈在于这层代理层,一挂全挂</li>
<li>自研产品维护成本高</li>
</ul>
<h1 id="6-相关文档"><a href="#6-相关文档" class="headerlink" title="6. 相关文档"></a>6. 相关文档</h1><ul>
<li><a target="_blank" rel="noopener" href="https://book.douban.com/subject/25900156/">《Redis设计与实现》- 黄健宏著</a></li>
<li><a target="_blank" rel="noopener" href="https://redis.io/documentation">Redis官方文档</a></li>
<li><a target="_blank" rel="noopener" href="http://www.redis.cn/documentation.html">Redis中文文档</a></li>
<li><a target="_blank" rel="noopener" href="https://github.com/CodisLabs/codis">Codis Github</a></li>
</ul>
</section>
    <!-- Tags START -->
    
      <div class="tags">
        <span>Tags:</span>
        
  <a href="/tags#Redis" >
    <span class="tag-code">Redis</span>
  </a>

      </div>
    
    <!-- Tags END -->
    <!-- NAV START -->
    
  <div class="nav-container">
    <!-- reverse left and right to put prev and next in a more logic postition -->
    
      <a class="nav-left" href="/2020/03/15/%E6%B5%85%E8%B0%88Java%E5%AF%B9%E8%B1%A1%E5%9B%9B%E5%A4%A7%E5%BC%95%E7%94%A8/">
        <span class="nav-arrow">← </span>
        
          浅谈Java对象四大引用
        
      </a>
    
    
      <a class="nav-right" href="/2020/04/17/Redis%E6%8C%81%E4%B9%85%E5%8C%96%E6%9C%BA%E5%88%B6/">
        
          Redis持久化机制
        
        <span class="nav-arrow"> →</span>
      </a>
    
  </div>

    <!-- NAV END -->
    <!-- 打赏 START -->
    
      <div class="money-like">
        <div class="reward-btn">
          赏
          <span class="money-code">
            <span class="alipay-code">
              <div class="code-image"></div>
              <b>使用支付宝打赏</b>
            </span>
            <span class="wechat-code">
              <div class="code-image"></div>
              <b>使用微信打赏</b>
            </span>
          </span>
        </div>
        <p class="notice">若你觉得我的文章对你有帮助，欢迎点击上方按钮对我打赏</p>
      </div>
    
    <!-- 打赏 END -->
    <!-- 二维码 START -->
    
      <div class="qrcode">
        <canvas id="share-qrcode"></canvas>
        <p class="notice">扫描二维码，分享此文章</p>
      </div>
    
    <!-- 二维码 END -->
    
      <!-- Utterances START -->
      <div id="utterances"></div>
      <script src="https://utteranc.es/client.js"
        repo="ltyeamin/blogtalks"
        issue-term="pathname"
        theme="github-light"
        crossorigin="anonymous"
        async></script>    
      <!-- Utterances END -->
    
  </article>
  <!-- Article END -->
  <!-- Catalog START -->
  
    <aside class="catalog-container">
  <div class="toc-main">
    <strong class="toc-title">Catalog</strong>
    
      <ol class="toc-nav"><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#1-Redis%E5%8D%95%E8%8A%82%E7%82%B9%E6%A8%A1%E5%BC%8F"><span class="toc-nav-text">1. Redis单节点模式</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#1-1-%E4%BC%98%E7%BC%BA%E7%82%B9%E5%AF%B9%E6%AF%94"><span class="toc-nav-text">1.1 优缺点对比</span></a></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#1-2-%E5%8D%95%E8%8A%82%E7%82%B9%E5%AE%89%E8%A3%85"><span class="toc-nav-text">1.2 单节点安装</span></a></li></ol></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#2-Redis%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E6%A8%A1%E5%BC%8F"><span class="toc-nav-text">2. Redis主从复制模式</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#2-1-%E4%BC%98%E7%BC%BA%E7%82%B9%E5%AF%B9%E6%AF%94"><span class="toc-nav-text">2.1 优缺点对比</span></a></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#2-2-%E6%90%AD%E5%BB%BA1%E4%B8%BB3%E4%BB%8E%E7%9A%84%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E6%9E%B6%E6%9E%84"><span class="toc-nav-text">2.2 搭建1主3从的主从复制架构</span></a></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#2-3-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E5%90%8C%E6%AD%A5%E8%BF%87%E7%A8%8B%E5%8E%9F%E7%90%86"><span class="toc-nav-text">2.3 主从复制同步过程原理</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-3-1-%E5%AE%8C%E6%95%B4%E5%90%8C%E6%AD%A5"><span class="toc-nav-text">2.3.1 完整同步</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-3-2-%E5%9C%A8%E7%BA%BF%E6%9B%B4%E6%96%B0"><span class="toc-nav-text">2.3.2 在线更新</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-3-3-%E5%A2%9E%E9%87%8F%E5%90%8C%E6%AD%A5"><span class="toc-nav-text">2.3.3 增量同步</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-3-4-%E6%97%A0%E7%A3%81%E7%9B%98%E5%A4%8D%E5%88%B6"><span class="toc-nav-text">2.3.4 无磁盘复制</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-3-5-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E8%AE%BE%E7%BD%AE%E4%BC%98%E5%8C%96"><span class="toc-nav-text">2.3.5 主从复制设置优化</span></a></li></ol></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#2-4-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E6%95%85%E9%9A%9C%E9%97%AE%E9%A2%98"><span class="toc-nav-text">2.4 主从复制故障问题</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-4-1-%E4%BB%8ERedis%E5%AE%95%E6%9C%BA"><span class="toc-nav-text">2.4.1 从Redis宕机</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-4-2-%E4%B8%BBRedis%E5%AE%95%E6%9C%BA"><span class="toc-nav-text">2.4.2 主Redis宕机</span></a></li></ol></li></ol></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#3-Redis%E5%93%A8%E5%85%B5%E6%A8%A1%E5%BC%8F"><span class="toc-nav-text">3. Redis哨兵模式</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#3-1-%E4%BC%98%E7%BC%BA%E7%82%B9%E5%AF%B9%E6%AF%94"><span class="toc-nav-text">3.1 优缺点对比</span></a></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#3-2-Sentinel%E6%90%AD%E5%BB%BA%E4%BD%BF%E7%94%A8"><span class="toc-nav-text">3.2 Sentinel搭建使用</span></a></li></ol></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#4-Redis-Cluster%E6%A8%A1%E5%BC%8F"><span class="toc-nav-text">4. Redis Cluster模式</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#4-1-%E4%BC%98%E7%BC%BA%E7%82%B9%E5%AF%B9%E6%AF%94"><span class="toc-nav-text">4.1 优缺点对比</span></a></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#4-2-%E5%9F%BA%E6%9C%AC%E7%89%B9%E6%80%A7"><span class="toc-nav-text">4.2 基本特性</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#4-2-1-%E5%A4%8D%E5%88%B6%E4%B8%8E%E9%AB%98%E5%8F%AF%E7%94%A8"><span class="toc-nav-text">4.2.1 复制与高可用</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#4-2-2-%E5%88%86%E7%89%87%E4%B8%8E%E9%87%8D%E5%88%86%E7%89%87"><span class="toc-nav-text">4.2.2 分片与重分片</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#4-2-3-%E9%AB%98%E6%80%A7%E8%83%BD"><span class="toc-nav-text">4.2.3 高性能</span></a></li></ol></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#4-3-Redis-Cluster%E6%9E%B6%E6%9E%84"><span class="toc-nav-text">4.3 Redis Cluster架构</span></a></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#4-4-%E6%89%8B%E5%8A%A8%E6%90%AD%E5%BB%BARedis-Cluster"><span class="toc-nav-text">4.4 手动搭建Redis Cluster</span></a></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#4-5-%E9%9B%86%E7%BE%A4%E6%95%85%E9%9A%9C%E6%9C%BA%E5%88%B6"><span class="toc-nav-text">4.5 集群故障机制</span></a></li></ol></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#5-%E8%87%AA%E7%A0%94Redis%E4%BB%A3%E7%90%86%E4%B8%AD%E9%97%B4%E4%BB%B6"><span class="toc-nav-text">5. 自研Redis代理中间件</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#5-1-Codis%E4%BB%A3%E7%90%86%E4%B8%AD%E9%97%B4%E4%BB%B6"><span class="toc-nav-text">5.1 Codis代理中间件</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#5-1-2-Codis%E7%AE%80%E4%BB%8B"><span class="toc-nav-text">5.1.2 Codis简介</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#5-1-2-%E4%BC%98%E7%BC%BA%E7%82%B9%E5%AF%B9%E6%AF%94"><span class="toc-nav-text">5.1.2 优缺点对比</span></a></li></ol></li></ol></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#6-%E7%9B%B8%E5%85%B3%E6%96%87%E6%A1%A3"><span class="toc-nav-text">6. 相关文档</span></a></li></ol>
    
  </div>
</aside>
  
  <!-- Catalog END -->
</main>

<script>
  (function () {
    var url = 'http://example.com/2020/04/01/了解常见的Redis集群方式/';
    var banner = ''
    if (banner !== '' && banner !== 'undefined' && banner !== 'null') {
      $('#article-banner').css({
        'background-image': 'url(' + banner + ')'
      })
    } else {
      $('#article-banner').geopattern(url)
    }
    $('.header').removeClass('fixed-header')

    // error image
    $(".markdown-content img").on('error', function() {
      $(this).attr('src', '/css/images/error_icon.png')
      $(this).css({
        'cursor': 'default'
      })
    })

    // zoom image
    $(".markdown-content img").on('click', function() {
      var src = $(this).attr('src')
      if (src !== '/css/images/error_icon.png') {
        var imageW = $(this).width()
        var imageH = $(this).height()

        var zoom = ($(window).width() * 0.95 / imageW).toFixed(2)
        zoom = zoom < 1 ? 1 : zoom
        zoom = zoom > 2 ? 2 : zoom
        var transY = (($(window).height() - imageH) / 2).toFixed(2)

        $('body').append('<div class="image-view-wrap"><div class="image-view-inner"><img src="'+ src +'" /></div></div>')
        $('.image-view-wrap').addClass('wrap-active')
        $('.image-view-wrap img').css({
          'width': `${imageW}`,
          'transform': `translate3d(0, ${transY}px, 0) scale3d(${zoom}, ${zoom}, 1)`
        })
        $('html').css('overflow', 'hidden')

        $('.image-view-wrap').on('click', function() {
          $(this).remove()
          $('html').attr('style', '')
        })
      }
    })
  })();
</script>


  <script>
    var qr = new QRious({
      element: document.getElementById('share-qrcode'),
      value: document.location.href
    });
  </script>






    <div class="scroll-top">
  <span class="arrow-icon"></span>
</div>
    <footer class="app-footer">
  <p class="copyright">
    &copy; 2024 | Proudly powered by <a href="https://hexo.io" target="_blank">Hexo</a>
    <br>
    Theme by <a target="_blank" rel="noopener" href="https://github.com/ltyeamin">tong.li</a>
  </p>
</footer>

<script>
  function async(u, c) {
    var d = document, t = 'script',
      o = d.createElement(t),
      s = d.getElementsByTagName(t)[0];
    o.src = u;
    if (c) { o.addEventListener('load', function (e) { c(null, e); }, false); }
    s.parentNode.insertBefore(o, s);
  }
</script>
<script>
  async("https://cdn.staticfile.org/fastclick/1.0.6/fastclick.min.js", function(){
    FastClick.attach(document.body);
  })
</script>

<script>
  var hasLine = 'true';
  async("https://cdn.staticfile.org/highlight.js/9.12.0/highlight.min.js", function(){
    $('figure pre').each(function(i, block) {
      var figure = $(this).parents('figure');
      if (hasLine === 'false') {
        figure.find('.gutter').hide();
      }
      hljs.configure({useBR: true});
      var lang = figure.attr('class').split(' ')[1] || 'code';
      var codeHtml = $(this).html();
      var codeTag = document.createElement('code');
      codeTag.className = lang;
      codeTag.innerHTML = codeHtml;
      $(this).attr('class', '').empty().html(codeTag);
      figure.attr('data-lang', lang.toUpperCase());
      hljs.highlightBlock(block);
    });
  })
</script>
<!-- Baidu Tongji -->



<script src='https://cdn.staticfile.org/mermaid/8.11.2/mermaid.min.js'></script>



<script src="/js/script.js"></script>


  </body>
</html>